/**
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

package pittypat;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map.Entry;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import java.math.BigDecimal;
import java.util.UUID;

/**
 * 表示一个可以动态添加属性的对象，属性名称不区分大小写，属性值的类型为 IJson。 该类型的对象实例同时可以方便地编写为 JSON
 * 字符串。FunctionModel.getOutArgs() 返回的就是该类型的对象实例。
 */
public final class DynamicModel implements IComplex {
	private HashMap<String, Object> map;

	/**
	 * 初始化 DynamicModel 类的新实例。
	 */
	public DynamicModel() {
		this.map = new HashMap<>();
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Object value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Boolean value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Byte value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, byte[] value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, LocalDateTime value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, LocalDate value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, LocalTime value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, IJson value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, BigDecimal value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Float value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Double value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Short value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Integer value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, Long value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, String value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 设置指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 * @param value
	 *            属性值。
	 */
	public void set(String name, UUID value) {
		if (name != null && name.length() > 0) {
			this.map.put(name, value);
		}
	}

	/**
	 * 获取指定名称的属性值。
	 * 
	 * @param name
	 *            属性名称。
	 */
	public Object get(String name) {
		return name == null || name.length() == 0 ? null : this.map.getOrDefault(name, null);
	}

	/**
	 * 将当前对象作为 JSON 字符串写入指定的文本流。
	 * 
	 * @param writer
	 *            目标文本流。
	 * @throws IOException
	 * @throws IllegalArgumentException
	 *             writer 为 null。
	 * @see pittypat.IJson#write(java.io.Writer)
	 */
	@Override
	public void write(Writer writer) throws IOException {
		if (writer == null) {
			throw new IllegalArgumentException("writer 为 null。");
		}

		writer.write('{');

		int count = this.map.size();
		int i = 0;

		for (Entry<String, Object> e : this.map.entrySet()) {
			writer.write("\"" + e.getKey() + "\":");
			Json.write(writer, e.getValue());
			if (i < count - 1) {
				writer.write(',');
			}
			++i;
		}

		writer.write('}');
	}

	/**
	 * 将当前对象转换为 JSON 字符串。
	 */
	@Override
	public String toString() {
		if (this.map.size() == 0) {
			return "{}";
		}
		
		StringWriter writer = new StringWriter();
		
		try {
			this.write(writer);
		} catch (IOException e) {
			return "";
		}
		
		return writer.toString();
	}
}
